package com.anan.builder;

import java.io.*;
import java.nio.charset.StandardCharsets;

public class BuildAspect {

    public static void create(String projectName) {

        String path = System.getProperty("user.dir") + "/" + projectName + "/src/main/java/com/anan/aspect";
        File file = new File(path);
        if (!file.exists()) {
            boolean mkdirs = file.mkdirs();
            if (!mkdirs) {
                throw new RuntimeException("创建 " + path + " 目录失败");
            }
        }
        File beanFile = new File(path, "GlobalOperatcionAspect.java");
        OutputStream out = null;
        OutputStreamWriter outw = null;
        BufferedWriter bw = null;
        try {
            out = new FileOutputStream(beanFile);
            outw = new OutputStreamWriter(out, StandardCharsets.UTF_8);
            bw = new BufferedWriter(outw);
            bw.write("package com.anan.aspect;\n" +
                    "\n" +
                    "\n" +
                    "import com.anan.annotation.CheckObject;\n" +
                    "import com.anan.annotation.GlobalInterceptor;\n" +
                    "import com.anan.annotation.CheckValue;\n" +
                    "import com.anan.exception.BusinessException;\n" +
                    "import com.anan.utils.AnanUtils;\n" +
                    "import com.anan.utils.RedisUtils;\n" +
                    "import org.aspectj.lang.JoinPoint;\n" +
                    "import org.aspectj.lang.annotation.Aspect;\n" +
                    "import org.aspectj.lang.annotation.Before;\n" +
                    "import org.aspectj.lang.annotation.Pointcut;\n" +
                    "import org.aspectj.lang.reflect.MethodSignature;\n" +
                    "import org.springframework.stereotype.Component;\n" +
                    "import org.springframework.web.context.request.RequestContextHolder;\n" +
                    "import org.springframework.web.context.request.ServletRequestAttributes;\n" +
                    "\n" +
                    "import javax.annotation.Resource;\n" +
                    "import javax.servlet.http.HttpServletRequest;\n" +
                    "import java.lang.reflect.Field;\n" +
                    "import java.lang.reflect.Method;\n" +
                    "import java.lang.reflect.Parameter;\n" +
                    "import java.util.Arrays;\n" +
                    "\n" +
                    "@Aspect\n" +
                    "@Component(\"globalOperatcionAspect\")\n" +
                    "public class GlobalOperatcionAspect {  // 全局切面  环绕通知  请求拦截\n" +
                    "\n" +
                    "    @Resource\n" +
                    "    RedisUtils<Object> redisUtils;\n" +
                    "\n" +
                    "    @Pointcut(\"@annotation(com.anan.annotation.GlobalInterceptor)\")  // 切面点  使用该注解的就会拦截\n" +
                    "    private void requestInterceptor() {}\n" +
                    "\n" +
                    "    // 以AccountController 类中的 login方法 login请求为例解释代码  进行 login请求\n" +
                    "\n" +
                    "    @Before(\"requestInterceptor()\")  // 前置通知\n" +
                    "    public void interceptorDo(JoinPoint point) throws BusinessException, ClassNotFoundException, IllegalAccessException {\n" +
                    "        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();\n" +
                    "        Object target = point.getTarget();  // 获取目标类对象  // AccountController类\n" +
                    "        // 获取调用方法时传入的实参\n" +
                    "        Object[] arguments = point.getArgs();  // 获取方法（切入点）的参数(传入的具体值)  // 切入点 执行的方法login方法  获取调用方法时传入的参数值 例 session（session 当前会话对象） root@qq.com（email 邮箱） C2DC426171FA602E28461ACB3E4FF204 （password 密码） 653424（checkCode 验证码\n" +
                    "        MethodSignature signature = (MethodSignature) point.getSignature();  // 获取连接点的签名对象，再将其转换为MethodSignature类型\n" +
                    "        Method method = signature.getMethod();  // 获取当前执行的方法对象\n" +
                    "//            String methodName = method.getName();  // 获取方法的名称  // login\n" +
                    "//            Class<?>[] parameterTypes = method.getParameterTypes();  // 获取方法形参的参数的类型  // HttpSession String String String\n" +
                    "        // 通过反射获得拦截的method\n" +
                    "//            Method method = target.getClass().getMethod(methodName, parameterTypes);\n" +
                    "        // 获取该方法的注解 （判断是否添加有 GlobalInterceptor 注解）\n" +
                    "        GlobalInterceptor interceptor = method.getAnnotation(GlobalInterceptor.class);\n" +
                    "        if(interceptor != null){\n" +
                    "            /**\n" +
                    "             * 校验登录\n" +
                    "             */\n" +
                    "            if (interceptor.checkLogin()) {\n" +
                    "                String token = request.getHeader(\"token\");\n" +
                    "                Object o = redisUtils.get(token);\n" +
                    "                if(o == null){\n" +
                    "                    throw new BusinessException(600,\"用户未登录 或 登录超时 请登录！\");\n" +
                    "                }\n" +
                    "            }\n" +
                    "            /**\n" +
                    "             * 校验参数\n" +
                    "             */\n" +
                    "            if (interceptor.checkParams()) {\n" +
                    "                validateParams(method, arguments);\n" +
                    "            }\n" +
                    "        }\n" +
                    "\n" +
                    "    }\n" +
                    "\n" +
                    "    /**\n" +
                    "     * @param m         调用的方法对象\n" +
                    "     * @param arguments 调用方法时传入的实参\n" +
                    "     * @throws BusinessException\n" +
                    "     */\n" +
                    "    private void validateParams(Method m, Object[] arguments) throws ClassNotFoundException, IllegalAccessException {\n" +
                    "        Parameter[] parameters = m.getParameters();  // 获取该方法对象的形参 所有形参的数组\n" +
                    "        for (int i = 0; i < parameters.length; i++) {  // 遍历所有参数  校验每一个参数\n" +
                    "            Parameter parameter = parameters[i];  // 获取该方法的形参对象\n" +
                    "            // 否则添加有该注解 继续进行\n" +
                    "            Object paramsObject = arguments[i];  // 获取调用方法时传入的实参的值  通过i 与形参一一对应 // root@qq.com\n" +
                    "            CheckObject checkObject = parameter.getAnnotation(CheckObject.class);\n" +
                    "            CheckValue checkValue = parameter.getAnnotation(CheckValue.class);  // 获取形参的指定注解 VerifyParam\n" +
                    "            // 对象类型校验\n" +
                    "            if (checkObject != null && checkObject.required()) {\n" +
                    "                String typeName = parameter.getParameterizedType().getTypeName();  // // 获取该方法的形参对象的类型名称  com.easypan.package.className  完整的类名名称\n" +
                    "                Class classz = Class.forName(typeName);\n" +
                    "                Field[] fields = classz.getDeclaredFields();  // 获取声明的字段 属性\n" +
                    "                String[] checkField = checkObject.checkProperties();  // 获取注解的checkProperties 的值 为数组 表示要校验的参数数组  默认是传入参数的属性名字符串组成的数\n" +
                    "                if(\"all\".equals(checkField[0])){  // 如果第一个参数值为 all 表示校验参数对象的所有属性\n" +
                    "                    for (Field field : fields){\n" +
                    "                        // 设置该字段为可以访问标志\n" +
                    "                        field.setAccessible(true);  // 将该字段设置为可访问\n" +
                    "                        Object resultValue = field.get(paramsObject);\n" +
                    "                        if(resultValue==null){\n" +
                    "                            throw new BusinessException(400,\"请求错误 缺少必要参数 参数参考 \"+Arrays.toString(fields));\n" +
                    "                        }\n" +
                    "                    }\n" +
                    "                }else{  // 如果第一个参数值不为 all 表示校验参数对象的指定属性\n" +
                    "                    for (Field field : fields){\n" +
                    "                        for (int j = 0; j < checkField.length; j++) {\n" +
                    "                            if (field.getName().equals(checkField[j])) {  // 如果 该声明的字段 等于 需要校验的字段\n" +
                    "                                field.setAccessible(true);  // 将该字段设置为可访问\n" +
                    "                                Object resultValue = field.get(paramsObject);  // 在指定对象中获取指定字段的值\n" +
                    "                                if (resultValue == null) {\n" +
                    "                                    throw new BusinessException(400, \"请求错误 缺少必要参数 \"+field.getName()+\" 参数参考 \"+Arrays.toString(fields));\n" +
                    "                                }\n" +
                    "                            }\n" +
                    "                        }\n" +
                    "                    }\n" +
                    "                }\n" +
                    "            }\n" +
                    "            // 基本类型校验\n" +
                    "            if(checkValue != null && checkValue.required()){\n" +
                    "                if(AnanUtils.stringIsEmpty(paramsObject)){  // 校验传入的参数对象是否为空\n" +
                    "                    throw new BusinessException(400, \"请求错误 缺少必要参数 \"+parameter.getName());\n" +
                    "                }\n" +
                    "            }\n" +
                    "        }\n" +
                    "    }\n" +
                    "\n" +
                    "\n" +
                    "}\n");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != bw) {
                try {
                    bw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (outw != null) {
                try {
                    outw.close();
                } catch (IOException e) {
                    e.printStackTrace();

                }
            }
            if (null != out) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
    }
}
